#pragma once
#include <windows.h>

//+==================================================================+
class Counter
{
	LARGE_INTEGER t0, t1, frequency;

	double period;								// windows performance counter period length

public:
//////////////////////////////////////////////////////////////////////
	Counter()
	{
		QueryPerformanceFrequency(&frequency);
	//----
	//	Frequency will be wrong when overclocking, by the overclocking factor.
	//	E.g. when a 2500 MHz CPU is overclocked to 3200 MHz, the factor is 1.28
	//	Unfortunately there is no simple way to tell CPU default and actual frequency. (OpenCL has this function, though)
//		frequency.QuadPart = LONGLONG(1.28*double(frequency.QuadPart)+0.5);
//		frequency.QuadPart = LONGLONG(0.78125*double(frequency.QuadPart)+0.5);
		period = 1.0 / frequency.QuadPart;
		QueryPerformanceCounter(&t0);
		t1 = t0;
	}

//+------------------------------------------------------------------+
	static __int64 Get()
	{
		LARGE_INTEGER temp;
		QueryPerformanceCounter(&temp);
		return temp.QuadPart;
	}

//+------------------------------------------------------------------+
	double	getPeriod()		const		{	return period;						}
	__int64	getFrequency()	const		{	return frequency.QuadPart;		}
	__int64	getStart()		const		{	return t0.QuadPart;				}
	__int64	getStop()		const		{	return t1.QuadPart;				}
	__int64	resultTicks()	const		{	return getStop()-getStart();	}
	void		start()						{	QueryPerformanceCounter(&t0);	t1 = t0;	}
	void		stop()						{	QueryPerformanceCounter(&t1);	}
	operator double()			const
	{
		LARGE_INTEGER tmp;
		QueryPerformanceCounter(&tmp);
		return period*(tmp.QuadPart-t0.QuadPart);
	}
//+------------------------------------------------------------------+
	double	result()			const
	{
		return period*(t1.QuadPart-t0.QuadPart);
	}
//+------------------------------------------------------------------+
//	time since start or last call to this function.
	double	getAndReset()
	{
		QueryPerformanceCounter(&t1);
		double result = period*(t1.QuadPart-t0.QuadPart);
		t0 = t1;
		return result;
	}
//+------------------------------------------------------------------+
//	resume counting after having been stopped.
	void		resume()
	{
		DWORD64 ticks = resultTicks();
		QueryPerformanceCounter(&t1);
		t0.QuadPart = t1.QuadPart - ticks;
	}
//+------------------------------------------------------------------+
//	set and return current time.
	double	set(double t)
	{
		DWORD64 ticks = DWORD64(t * double(frequency.QuadPart) + 0.5);
		QueryPerformanceCounter(&t1);
		t0.QuadPart = t1.QuadPart - ticks;
		return result();
	}

};

